#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
#include <cassert>

#include "LeaderBoard.h"
#include "menu.h"
#include "DEBUG.h"

using namespace std;

player leaderboard [MAX_PLAYER];


void DrawBttn (bttnbox thisb);

//=======================================
// INPUT/OUTPUT FUNCTION
//=======================================

bool LoadLeaderBoard(){

  /*
  * We use the variable file to open the classifica.dat in input.
  * We return false if the file doesn't exist.
  */
  ifstream file("./../res/classifica.dat");
  if(!file){
    cerr<<"ERROR: The file 'classifica' doesn't exist.\n";
    return false;
  }  
  file.seekg(0);
  
  /*
  * The MAX_CHAR_PER_LINE define the maximum amount of characters we can
  * find in a line of the file classifica.dat.
  */
  const int MAX_CHAR_PER_LINE = 11;

  /*
  * The buf is a char pointer and is used like a buffer for when the 
  * software read a line of the .dat file.
  */
  char array_char[MAX_CHAR_PER_LINE];
  char *buf = array_char;
  
  /*
  * In the following list we can find five support variables for the while cycle
  * in which the software read, reinterpret, and save on the leaderboard
  * struct all the content of the file classifica.dat :
  * playerCounter is a integer variable. It stores the number of the line 
  * we are reading in the file .dat and also the current element we are going to 
  * define in the leaderboards structure.
  * namePos is a interger variable. It stores the information about the actual
  * empty position in the supName variable.
  * supName is a support character array that stores the name of the player
  * in the actual line of the file classifica.dat
  * scorePos is a interger variable. It stores the information about the actual
  * empty position in the supScore variable.
  * supScore is a support character array that stores the score of the player
  * in the actual line of the file classifica.dat
  */
  int playerCounter=0;
  unsigned int namePos=0;
  char supName[MAX_CHAR_NAME];
  unsigned int scorePos= 0;
  char supScore[MAX_SCORE];
  
	// read each line of the file until the end of the file (eof)
  while (!file.eof()){
    // read an entire line and store it in the buf
    
    file.getline(buf, MAX_CHAR_PER_LINE);
    
    unsigned int i = 0;
       
    while (i< MAX_CHAR_PER_LINE){
      if((scorePos < MAX_SCORE) && 
         (buf[i] <='9' && '0'<= buf[i]) ){
        supScore[scorePos] = buf[i];			
	scorePos++;
      }
      else if (namePos < (MAX_CHAR_NAME) && 
               ((buf[i] <='Z' && 'A'<= buf[i]) || (buf[i] <='z' && 'a'<= buf[i]))){
        supName[namePos]=buf[i];
	namePos++;
      }
      i++;
    }
     
    //initialize the leaderboard
    for (unsigned int j = 0; j<MAX_CHAR_NAME; j++){
      leaderboard[playerCounter].name[j]=supName[j];
    }
    leaderboard[playerCounter].points = atoi(supScore);
    
    D2(cout<<"Player Name: "<<leaderboard[playerCounter].name
      <<"Player Score: "<<leaderboard[playerCounter].points<<endl)    
      
    //put the support variables in the correct state for the next cycle.
    for (unsigned int j = 0 ; j<MAX_SCORE; j++){
      supScore[j] = '!';
    }
    playerCounter++;
    namePos=0;
    scorePos=0;
    }
  D2(cout<<"\nNOMI:\t PUNTEGGIO:\t \n"	;)
  D2(for (unsigned int i = 0; i<MAX_PLAYER; i++)
     cout<<leaderboard[i].name<<"\t"<<leaderboard[i].points<<"\t\n";)
    
  file.close();  
  return true;
}

void ShowLeaderBoard(const int width, const int height, bttnbox bttn[]){
  /*
   * Here we initialize all the variables that we need for the display drawing.
   * sNameX is the x position where we start drawing the names of the players
   * startY is the y position where we start drawing
   * sScoreX is the x position where we start drawing the scores
   * scatter is the amount of pixel between two different lines.
   */
  const unsigned int sNameX = width/2-width/4; 
  const unsigned int startY = height/2-height/6;
  const unsigned int sScoreX = width/2+width/6;
  const unsigned int scatter = 20;
  ALLEGRO_FONT* font20 = al_load_font("./../res/NEWACADEMY.ttf", 20, 0);   
  
  char gameName [] = "Leader Board";
  
  int textLenght = al_get_text_width(font50, gameName);
  
  al_draw_text(font50, al_map_rgb(255,255,255), width/2- textLenght/2, height-(height - height/4),0, gameName);
  
  //this variable keeps memory of the line we are going to draw, so we can draw
  //this line text at the right y position.
  int line= 0;
  
  for (unsigned int j=0; j<MAX_PLAYER; j++){
    al_draw_text(font20, al_map_rgb(255,255,255), sNameX, startY+line, 0, leaderboard[j].name);
    al_draw_textf(font20, al_map_rgb(255,255,255), sScoreX, startY+line,0,  "%d", leaderboard[j].points);
    line += scatter;
  }
   
  DrawBttn(bttn[back]);
}


bool SaveScore (int score){
  if( leaderboard[MAX_PLAYER].points < score){ 
    /*Creating a string storing the information about the player name that can 
    store ALLEGRO CHARS*/
    ALLEGRO_USTR *support_string;
    support_string = al_ustr_new("");
    /*Creating an array of char that contains the default name a it will be used
     like an interface for communication between the array of char in the 
     leaderboard and the allegro unichar string.*/
    char p_name[MAX_CHAR_NAME+1] = "AAA";
    
    const char * key_push = new char[4];        
    /*Counter takes memory of the actual position in the name*/
    unsigned int counter=0;
    bool insert_complete = false;
    unsigned int act_pos = 1;
    
    while (!insert_complete){
      al_wait_for_event(event_queue, &ev);
         
      if (ev.type == ALLEGRO_EVENT_KEY_CHAR){
        if (ev.keyboard.keycode == ALLEGRO_KEY_ENTER){
          insert_complete = true;
        } else if( counter>0 && ev.keyboard.keycode == ALLEGRO_KEY_BACKSPACE){
          al_ustr_remove_chr(support_string, counter);
          counter--;
          p_name[counter] ='A';
          D1(cout<<p_name<<endl;)
        } else if (counter<MAX_CHAR_NAME){
	        if (ev.keyboard.keycode >= ALLEGRO_KEY_A && ev.keyboard.keycode <= ALLEGRO_KEY_Z){ 
            al_ustr_insert_chr(support_string, counter,ev.keyboard.unichar);
            key_push = al_cstr(support_string);
            p_name[counter]=key_push[counter];
            counter++;
            D1(cout<<p_name<<endl;)
	        }
        }
      }
      
      if(act_pos != counter){
        act_pos = counter;
        DrawSaveScore(p_name);
        //inserire qui display delle lettere o metterlo in draw save score
        al_flip_display();
        al_clear_to_color(al_map_rgb(0,0,0));
      }
    }

    leaderboard[MAX_PLAYER-1].points = score;
    for (unsigned int i = 0; i<MAX_CHAR_NAME; i++)
      leaderboard[MAX_PLAYER-1].name[i] = p_name[i];
    
    BoardHeapSort();
    
    ofstream ofile("./../res/classifica.dat");
    if(!ofile){
      cerr<<"ERRORE: I can't open the file classifica.dat.\n";
      return 1;
  	}
    //salvataggio su file	
    for (unsigned int i = 0; i<MAX_PLAYER; i++){
      ofile<<leaderboard[i].name<<" "<<leaderboard[i].points<<"\n";
    }
    
    ofile.close();
    al_flip_display();
    al_clear_to_color(al_map_rgb(0,0,0));
  }
  return Menu();
}

void DrawSaveScore (char p_name[]){
  char temp_0 = p_name[0];
  char temp_1 = p_name[1];
  char temp_2 = p_name[2];
  const char d_title []="INSERT NAME:";
  const char d_info_0 [] ="Use your keyboard";
  const char d_info_1 []="Are supported 3 characters from A to Z.";
  const char d_info_2 []="Use ENTER to confirm";
        
  ALLEGRO_FONT* font12;
  ALLEGRO_FONT* font16;
         
  font12 = al_load_font("./../res/NEWACADEMY.ttf",12,0);
  font16 = al_load_font("./../res/NEWACADEMY.ttf",16,0);
  
  assert(font12);
  assert(font16);
    
  int text_lenght_title = al_get_text_width( font16,d_title );
  int text_lenght_info_0 = al_get_text_width( font12,d_info_0 );
  int text_lenght_info_1 = al_get_text_width( font12,d_info_1 );
  int text_lenght_info_2 = al_get_text_width( font12,d_info_2 );
       
  al_draw_text(font16,al_map_rgb(255,255,255), (WIDTH_DISPLAY-text_lenght_title)/2, (HEIGHT_DISPLAY/3),0,d_title);
  al_draw_text(font12,al_map_rgb(255,255,255), (WIDTH_DISPLAY-text_lenght_info_0)/2,(HEIGHT_DISPLAY/3)+15,0, d_info_0);
  al_draw_text(font12,al_map_rgb(255,255,255), (WIDTH_DISPLAY-text_lenght_info_1)/2,(HEIGHT_DISPLAY/3)+25,0, d_info_1);
  al_draw_text(font12,al_map_rgb(255,255,255), (WIDTH_DISPLAY-text_lenght_info_2)/2,(HEIGHT_DISPLAY/3)+35,0, d_info_2);
  
  al_draw_line( (WIDTH_DISPLAY/2) -10,(HEIGHT_DISPLAY/3)*2 +20,(WIDTH_DISPLAY/2) +10,(HEIGHT_DISPLAY/3)*2 +20,al_map_rgb(255,255,255), 2 );
  al_draw_textf(font16,al_map_rgb(255,255,255), (WIDTH_DISPLAY/2) -6,(HEIGHT_DISPLAY/3)*2 +5,0, "%c", temp_1);
  al_draw_line( (WIDTH_DISPLAY/2) -35,(HEIGHT_DISPLAY/3)*2 +20,(WIDTH_DISPLAY/2) -15,(HEIGHT_DISPLAY/3)*2 +20,al_map_rgb(255,255,255), 2 );
  al_draw_textf(font16, al_map_rgb (255,255,255), (WIDTH_DISPLAY/2) -31,(HEIGHT_DISPLAY/3)*2 +5, 0, "%c", temp_0);
  al_draw_line( (WIDTH_DISPLAY/2) +15,(HEIGHT_DISPLAY/3)*2 +20,(WIDTH_DISPLAY/2) +35,(HEIGHT_DISPLAY/3)*2 +20,al_map_rgb(255,255,255), 2 );
  al_draw_textf(font16, al_map_rgb (255,255,255), (WIDTH_DISPLAY/2) +19,(HEIGHT_DISPLAY/3)*2 +5, 0, "%c", temp_2);
}

int MaxScore(){
  return leaderboard[0].points;
}

//===========================
//  SORTING FUNCTIONS
//===========================

void MinHeapify(player* pList, int low, int high){
  int father = low;
  //this check if the left son is bigger than the last available position of
  //the array and bring the smaller array in the position of the father. And if
  //the actual father position is a "leaf" of the mean heap.
  while ((father*2)+1 <= high){
    int left = (father * 2) + 1;
    int right = left + 1;
    int minimum = father;
        
    D1(cout<<"FMinimum: "<<minimum<<endl);
    D2(cout<<"This is the minimum copied from the father "<<minimum<<endl);
        
    //Check if father is smaller than left child
    if (pList[minimum].points > pList[left].points){
      minimum = left;
           
      D1(cout<<"LMinimum: "<<minimum<<endl)
      D2(cout<<"This is the minimum copied from the left child "<<minimum<<endl);
    }
    //Check if the right child exist and if it is smaller than the minimum
    if ((right <= high) && (pList[minimum].points > pList[right].points)){
      minimum = right;
            
      D1(cout<<"RMinimum: "<<minimum<<endl);
      D2(cout<<"This is the minimum copied from the right child "<<minimum<<endl);
    }
    //Is the smaller element position equal to the father?
    if (minimum != father){
      player tmp = pList[father];
      pList[father] = pList[minimum];
      pList[minimum] = tmp;
      father = minimum;
            
      D2(cout<<"The MinHeapify has found a new minimum "<<endl);
      D2(cout<<"This is the old NAME of the father "<<tmp.name<<endl);
      D2(cout<<"This is the old VALUE of the father "<<tmp.points<<endl);
      D2(cout<<"This is the new NAME of the father "<<pList[father].name<<endl);
      D2(cout<<"This is the new VALUE of the father "<<pList[father].points<<endl);
      D2(cout<<"This is the new NAME of the old minimum son "<<pList[minimum].name<<endl);
      D2(cout<<"This is the new VALUE of the old minimum son "
              <<pList[minimum].points<<endl);
    }
    else{
      D2(cout<<"The father is in the correct position,"
            <<"he is the minimum of this sub-heap."<<endl);
      break;
    }
  }
  D2(cout<<"The father became a leaf of the minimum Heap"<<endl);
  return;
}

void BuildMinHeap(player* pList, int low, int high){
  //the start of the cycle is the middle of the array so the left or the right 
  //child of this element will be the last element in the array.
  int mid = (high - low -1)/2;
    
  D1(cout<<"This is the mid position for the BuildMinHeap "<<mid<<endl);
   
  while (mid >= 0){
    MinHeapify(pList, mid, high);
    --mid;
    D2(cout<<"This is the ACTUAL mid position: "<<mid<<endl);
  }
  return;
}

void BoardHeapSort(){
  player *pList = leaderboard;
  assert(pList);
  int high = MAX_PLAYER - 1;
  BuildMinHeap(pList, 0, high);
    
  D2(cout<<"This last position of the player on the array "<<high<<endl);
    
  while (high > 0){
    //This swap the first position, the minimum element, with the element
    //last position in the array and decrase the array size.
    player tmp = pList[high];
    pList[high] = pList[0];
    pList[0] = tmp;
    --high;
    D2(cout<<"This is the Actual Maximum Position: "<<high<<endl);
    MinHeapify(pList, 0, high);
  }
  D2(cout<<"\nNOMI:\t PUNTEGGIO:\t \n"	;)
  D2(for (unsigned int i = 0; i<MAX_PLAYER; i++) 
       cout<<leaderboard[i].name<<"\t"<<leaderboard[i].points<<"\t\n");
}
